/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stddef.h>
#include "sle_ssap_server_hal.h"
#include "sle_ssap_server_hdi.h"
#include "sle_hilog.h"
#include "sle_loader_hal.h"
#include <stdio.h>
#include <string.h>

static SleSsapsHdiOpts *g_sleSsapsHalOpts = NULL;
static SleSsapsHdiCallbacks *g_sleSsapsHdiCbks = NULL;
static SleSsapsHalCallbacks *g_sleSsapsHalCbks = NULL;

static void OnSleHdiSsapsStartServiceCallback(uint8_t serverId, uint16_t handle, SleHdiErrorCode errCode)
{
    SLE_LOGI("OnSleHdiSsapsStartServiceCallback serverId(%{public}d) errCode(0x%{public}08X)", serverId, errCode);
    if(g_sleSsapsHalCbks != NULL && g_sleSsapsHalCbks->OnSsapsServiceStartedCb != NULL) {
        SleHalErrorCode halErrcode = SleHalGetErrorCode(errCode);
        g_sleSsapsHalCbks->OnSsapsServiceStartedCb(serverId, handle, halErrcode);
    }
}

static void OnSleHdiSsapsDeleteAllServiceCallback(uint8_t serverId, SleHdiErrorCode errCode)
{
    SLE_LOGI("OnSleHdiSsapsDeleteAllServiceCallback serverId(%{public}d) errCode(0x%{public}08X)", serverId, errCode);
    if(g_sleSsapsHalCbks != NULL && g_sleSsapsHalCbks->OnSsapsAllServiceRemovedCb != NULL) {
        SleHalErrorCode halErrcode = SleHalGetErrorCode(errCode);
        g_sleSsapsHalCbks->OnSsapsAllServiceRemovedCb(serverId, halErrcode);
    }
}

static void OnSleHdiSsapsReadRequestCallback(uint8_t serverId, uint16_t connectId, const SsapsReqReadCbParam *readCbPara,
    SleHdiErrorCode errCode)
{
    if(g_sleSsapsHalCbks != NULL && g_sleSsapsHalCbks->OnSsapsRecvReadReqCb != NULL) {
        SleHalErrorCode halErrcode = SleHalGetErrorCode(errCode);
        g_sleSsapsHalCbks->OnSsapsRecvReadReqCb(serverId, connectId, readCbPara, halErrcode);
    }
}

static void OnSleHdiSsapsWriteRequestCallback(uint8_t serverId, uint16_t connectId, const SsapsReqWriteCbPara *writeCbPara,
    SleHdiErrorCode errCode)
{
    if(g_sleSsapsHalCbks != NULL && g_sleSsapsHalCbks->OnSsapsRecvWriteReqCb != NULL) {
        SleHalErrorCode halErrcode = SleHalGetErrorCode(errCode);
        g_sleSsapsHalCbks->OnSsapsRecvWriteReqCb(serverId, connectId, writeCbPara, halErrcode);
    }
}

static void OnSleHdiSsapsMtuChangedCallback(uint8_t serverId, uint16_t connectId, const SsapMtuInfo *info, SleHdiErrorCode errCode)
{
    SLE_LOGI("OnSleHdiSsapsMtuChangedCallback connectId(%{public}d) mtu(%{public}d) errCode(0x%{public}08X)", connectId, info->mtuSize, errCode);
    if(g_sleSsapsHalCbks != NULL && g_sleSsapsHalCbks->OnSsapsMtuChangeCb != NULL) {
        SleHalErrorCode halErrcode = SleHalGetErrorCode(errCode);
        g_sleSsapsHalCbks->OnSsapsMtuChangeCb(serverId, connectId, info, halErrcode);
    }
}

SleHalErrorCode InitSleSsapsHal(void)
{
    SLE_LOGI("InitSleSsapsHal");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_sleSsapsHalOpts == NULL, SLE_HAL_SUCCESS, "sleSsapsHall has been Inited");
    SleHalErrorCode ret = SLE_HAL_ERR_UNKNOWN;
    g_sleSsapsHalOpts = (SleSsapsHdiOpts *)malloc(sizeof(SleSsapsHdiOpts));
    ret = GetSleSsapsHalOpts(g_sleSsapsHalOpts);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "GetSleSsapsHalOpts fail(%{public}d)", ret);
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapsHalOpts != NULL, SLE_HAL_ERR_COMMON);
    if (g_sleSsapsHdiCbks == NULL) {
        g_sleSsapsHdiCbks = (SleSsapsHdiCallbacks *)malloc(sizeof(SleSsapsHdiCallbacks));
        g_sleSsapsHdiCbks->OnServiceStartedCb = OnSleHdiSsapsStartServiceCallback;
        g_sleSsapsHdiCbks->OnAllServiceRemovedCb = OnSleHdiSsapsDeleteAllServiceCallback;
        g_sleSsapsHdiCbks->OnRecvReadReqCb = OnSleHdiSsapsReadRequestCallback;
        g_sleSsapsHdiCbks->OnRecvWriteReqCb = OnSleHdiSsapsWriteRequestCallback;
        g_sleSsapsHdiCbks->OnMtuChangedCb = OnSleHdiSsapsMtuChangedCallback;
        SLE_ASSERT_AND_RETURN_RET_LOG(g_sleSsapsHdiCbks != NULL, SLE_HAL_ERR_DRIVER_OR_SYSTEM, "SleHal or SleDriver has not been inited");
    }
    SleHdiErrorCode result = g_sleSsapsHalOpts->registerServerCbks(g_sleSsapsHdiCbks);
    ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "registerServerCbks fail(0x%{public}08X)", result);
    g_sleSsapsHalCbks = (SleSsapsHalCallbacks*)malloc(sizeof(SleSsapsHalCallbacks));
    return ret;
}

SleHalErrorCode DeinitSleSsapsHal(void)
{
    SLE_LOGI("DeinitSleSsapsHal");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_sleSsapsHalOpts != NULL, SLE_HAL_SUCCESS, "sleSsapsHall has not been Inited");
    free(g_sleSsapsHalOpts);
    g_sleSsapsHalOpts = NULL;
    free(g_sleSsapsHdiCbks);
    g_sleSsapsHdiCbks = NULL;
    free(g_sleSsapsHalCbks);
    g_sleSsapsHalCbks = NULL;
    return SLE_HAL_SUCCESS;
}

SleHalErrorCode SleSsapsHalAddServer(const SleUuid *appUuid, uint8_t *serverId)
{
    SLE_LOGI("SleSsapsHalAddServer");
    SLE_ASSERT_AND_RETURN_RET(appUuid != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(serverId != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapsHalOpts->registerServer(appUuid, serverId);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "registerServer fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalRemoveServer(uint8_t serverId)
{
    SLE_LOGI("SleSsapsHalRemoveServer");
    SleHdiErrorCode result = g_sleSsapsHalOpts->unregisterServer(serverId);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "unregisterServer fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalAddService(uint8_t serverId, const SleUuid *serviceUuid, bool is_primary, uint16_t *serviceHandle)
{
    SLE_LOGI("SleSsapsHalAddService");
    SLE_ASSERT_AND_RETURN_RET(serviceUuid != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(serviceHandle != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapsHalOpts->addService(serverId, serviceUuid, is_primary, serviceHandle);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "addService fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalAddProperty(uint8_t serverId, uint16_t serviceHandle, const SsapsPropertyParam *property, uint16_t *propertyHandle)
{
    SLE_LOGD("SleSsapsHalAddProperty");
    SLE_ASSERT_AND_RETURN_RET(property != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(propertyHandle != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapsHalOpts->addProperty(serverId, serviceHandle, property, propertyHandle);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "addProperty fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalAddDescriptor(uint8_t serverId, uint16_t serviceHandle, uint16_t propertyHandle
        , const SsapsDescriptorParam *descriptor, uint16_t *descriptorHandle)
{
    SLE_LOGD("SleSsapsHalAddDescriptor");
    SLE_ASSERT_AND_RETURN_RET(descriptor != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(descriptorHandle != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapsHalOpts->addDescriptor(serverId, serviceHandle, propertyHandle, descriptor, descriptorHandle);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "addDescriptor fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalStartService(uint8_t serverId, uint16_t serviceHandle)
{
    SLE_LOGI("SleSsapsHalStartService");
    SleHdiErrorCode result = g_sleSsapsHalOpts->startService(serverId, serviceHandle);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "startService fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalRemoveAllServices(uint8_t serverId)
{
    SLE_LOGI("SleSsapsHalRemoveAllServices");
    SleHdiErrorCode result = g_sleSsapsHalOpts->deleteAllServices(serverId);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "deleteAllServices fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalSendResponse(uint8_t serverId, uint16_t connectId, const SsapsSendRspParam *rspParam)
{
    SLE_LOGD("SleSsapsHalSendResponse");
    SLE_ASSERT_AND_RETURN_RET(rspParam != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapsHalOpts->sendResponse(serverId, connectId, rspParam);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "sendResponse fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalNotifyIndicate(uint8_t serverId, uint16_t connectId, const SsapsNotifyParam *notifyParam)
{
#if 0
    SLE_LOGD("SleSsapsHalNotifyIndicate");
#endif
    SLE_ASSERT_AND_RETURN_RET(notifyParam != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapsHalOpts->sendNotifyIndicate(serverId, connectId, notifyParam);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "sendNotifyIndicate fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalNotifyIndicateByUuid(uint8_t serverId, uint16_t connectId, const SsapsNotyfyByUuidParam *notifyParam)
{
    SLE_LOGD("SleSsapsHalNotifyIndicateByUuid");
    SLE_ASSERT_AND_RETURN_RET(notifyParam != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapsHalOpts->sendNotifyIndicateByUuid(serverId, connectId, notifyParam);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "sendNotifyIndicateByUuid fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalSetMtuInfo(uint8_t serverId, const SsapMtuInfo *mtuInfo)
{
    SLE_LOGI("SleSsapsHalSetMtuInfo mtu(%u)", mtuInfo->mtuSize);
    SLE_ASSERT_AND_RETURN_RET(mtuInfo != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapsHalOpts->setServerMtuInfo(serverId, mtuInfo);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "setServerMtuInfo fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapsHalRegisterCallbacks(const SleSsapsHalCallbacks *callback)
{
    SLE_LOGI("SleSsapsHalRegisterCallbacks");
    SLE_ASSERT_AND_RETURN_RET(callback != NULL, SLE_HAL_ERR_INVALID_PARAM);
    memcpy(g_sleSsapsHalCbks, callback, sizeof(SleSsapsHalCallbacks));
    return SLE_HAL_SUCCESS;
}